﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using Furion;
using System.Threading;
using Microsoft.AspNetCore.Builder;
using OneOf.Types;
using Microsoft.AspNetCore.Http;
using Furion.Logging;
using TMV.Application.Tr.Services;
using Microsoft.Extensions.DependencyInjection;
using TMV.DTO.Authorization;
using StackExchange.Profiling.Internal;
using TMV.Application.SocketConfig.Service;
using Microsoft.AspNetCore.SignalR;
using Microsoft.Extensions.Hosting;
using TMV.DTO;
using TMV.Application.Home.Services;
using TMV.DTO.SocketConfig;
using NPOI.SS.Formula.Functions;
using TMV.Application.Car.Services;
using Furion.LinqBuilder;
using Org.BouncyCastle.Asn1.X509;
using Microsoft.Extensions.Caching.Memory;
using Newtonsoft.Json;
using TMV.Application.Abnormal.Servives;

namespace TMV.Web.Core.SocketServer
{
    public static class SocketService
    {
        static IMemoryCache _memoryCache;

        static ITrServiceDM trServiceDM { get; set; }
        static IHomeServiceDM homeServiceDM { get; set; }
        static ICarServiceDM carServiceDM { get; set; }
        static IAbnormalServiceDM abnormalServiceDM { get; set; }

        static IHubContext<ChatHub> _hubContext;
        static List<SocketConfigDto> clientScoketLis = new();
        static List<Socket> clientScoket = new();
        static ISocketConfigService socketConfigService { get; set; }
        public static void SocketServereMildd(this IApplicationBuilder app)
        {
            try
            {
                var al = app.ApplicationServices;
                trServiceDM = al.GetService<ITrServiceDM>();
                homeServiceDM = al.GetService<IHomeServiceDM>();
                carServiceDM = al.GetService<ICarServiceDM>();
                abnormalServiceDM = al.GetService<IAbnormalServiceDM>();

                _memoryCache = al.GetService<IMemoryCache>();

                socketConfigService = al.GetService<ISocketConfigService>();
                _hubContext = (IHubContext<ChatHub>)al.GetService(typeof(IHubContext<ChatHub>));
                var ReceiveIp = App.GetConfig<SocketConfigs>("SocketConfigs");
                clientScoketLis = socketConfigService.GetSocketConfig().Data;
                var socketListener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                ServerEnd(ReceiveIp.Port, 10, socketListener);
                //Thread th = new Thread(ServerCommunity);
                ThreadPool.QueueUserWorkItem(new WaitCallback(ServerCommunity), socketListener);
                // th.Start(socketListener);
            }
            catch (Exception ex)
            {
                ShowMsg("socketServer：" + ex.Message);
            }
        }
        static void ServerEnd(int myPort, int allowNum, Socket socketListener)
        {
            IPAddress ip = IPAddress.Any;
            int port = myPort;
            IPEndPoint point = new IPEndPoint(ip, port);
            socketListener.Bind(point);
            ShowMsg($"Listening...{ip}:{port}");
            socketListener.Listen(allowNum);
        }

        static void ServerCommunity(object obListener)
        {
            Socket temp = (Socket)obListener;
            Socket socketSender = null;
            while (true)
            {
                socketSender = temp.Accept();
                ShowMsg(("客户IP" + socketSender.RemoteEndPoint.ToString()) + " 连接成功");

                var ip = socketSender.RemoteEndPoint.ToString().Substring(0, socketSender.RemoteEndPoint.ToString().IndexOf(':'));
                if (!clientScoketLis.Any(x => x.Ip == ip))
                {
                    ShowMsg($"该{ip}地址不在配置中，无法连接，请添加配置后再连接");
                    socketSender.Close();
                }
                else
                {
                    socketConfigService.UpdateStatus(ip, true);
                    //var ip = socketSender.RemoteEndPoint.ToString().Substring(0, socketSender.RemoteEndPoint.ToString().IndexOf(':'));
                    //将所有客户端链接存入clientScoketLis集合 如果客户端socket重连了直接根据ip地址更新数据

                    if (clientScoket.Any(x => x.RemoteEndPoint.ToString().Substring(0, x.RemoteEndPoint.ToString().IndexOf(':')) == ip))
                    {
                        clientScoket.ForEach(x =>
                        {
                            if (x.RemoteEndPoint.ToString().Substring(0, x.RemoteEndPoint.ToString().IndexOf(':')) == ip)
                            {
                                x = socketSender;
                            }

                        });
                    }
                    else
                    {
                        clientScoket.Add(socketSender);
                        ShowMsg($"当前连接数:{clientScoket.Count()}");
                    }
                    ThreadPool.QueueUserWorkItem(new WaitCallback(ReceiveClient), socketSender);
                }
            }
        }

        static void ReceiveClient(object mySocketSender)
        {
            Socket socketSender = mySocketSender as Socket;
            var ip = socketSender.RemoteEndPoint.ToString().Substring(0, socketSender.RemoteEndPoint.ToString().IndexOf(':'));
            //try
            //{
            while (true)
            {
                byte[] buffer = new byte[1024];
                int rece = socketSender.Receive(buffer);
                string clientMsg = Encoding.GetEncoding("GBK").GetString(buffer, 0, rece);
                if (!clientMsg.IsNullOrEmpty())
                {
                    var rs = tmvdata(clientMsg);
                    if (rs != null)
                    {
						//Byte[] bytesSent = Encoding.GetEncoding("GBK").GetBytes(rs);
						//var sd = socketSender.Send(bytesSent, bytesSent.Length, 0);
						ShowMsg("TMV业务返回：" + rs.Message);
						//告警信息
						//ResultInfo ri = rs.FromJson<ResultInfo>();
						if (rs.Error != "0")
                        {
                            _hubContext.Clients.All.SendAsync("ReceiveMessage", "warning", rs.ToJson());
                        }
                    }
                }
            }
            //}
            //catch (Exception ex)
            //{
            //    socketConfigService.UpdateStatus(ip, false);
            //    ShowMsg($"{ip}{ex.Message}");
            //    //socketSender.Close();

            //}

        }

        static ResultInfo tmvdata(string msgStr)
        {
            try
            {
                ShowMsg("-------------------------------------------------------------------------------------");
                ShowMsg("接收数据:" + msgStr);
                var qdata = msgStr.FromJson<AuthorizationDTO>();


                if (qdata == null)
                {
                    // ShowMsg("未解析出数据");
                    return null;
                }
                //我们系统单位是吨，这里传过来的是千克
                qdata.Weight = qdata.Weight / 1000M;

                ResultInfo rdata = new ResultInfo();


                if (qdata.PlateNumber != null)
                {
                    #region 拦截同一时间多次推送的
                    string key = qdata.PlateNumber + "record";
                    if (!TimeLj(key))
                    {
                        var dd = homeServiceDM.GetHomeTransportationRecord(qdata.PlateNumber).Data;
                        if (dd != null)
                        {
                            dd.Huanjie = qdata.ProcessStatus;
                            _hubContext.Clients.All.SendAsync("ReceiveMessage", "record", dd.ToJson());
                        }
                    }
                    #endregion
                }
                if (qdata.Error != 0)
                {
                    #region 拦截同一时间多次推送的
                    string key = qdata.PlateNumber + qdata.Error + "jllc";
                    if (!TimeLj(key))
                    {
                        #region 记录流程数据
                        string dd = abnormalServiceDM.GetAbnormalData(qdata.Error);
                        _hubContext.Clients.All.SendAsync("ReceiveMessage", "warning", dd);
                        #endregion
                    }

                    #endregion
                }

                if (qdata.ProcessStatus != 0)
                {
                    #region 拦截同一时间多次推送的
                    string key = qdata.PlateNumber + "jllc";
                    if (!TimeLj(key))
                    {
                        #region 记录流程数据
                        trServiceDM.AddScalageRecords(qdata);
                        #endregion
                    }
                    #endregion
                }

                if (qdata.ProcessStatus == 1)
                {

                    #region 拦截同一时间多次推送的
                    string key = qdata.PlateNumber + "bk";
                    if (!TimeLj(key))
                    {
                        //绑卡
                        rdata = trServiceDM.GetDataInfo1(qdata);
                    }
                    #endregion
                }
                if (qdata.ProcessStatus == 4 && qdata.Inside == 1 && qdata.Finish == 1 && qdata.State == 1)
                {

                    //衡实时信息
                    _hubContext.Clients.All.SendAsync("ReceiveMessage", "HengZ", qdata.ToJson());
                    #region 拦截同一时间多次推送的
                    string key = qdata.PlateNumber + "mz";
                    if (!TimeLj(key))
                    {
                        //毛重
                        rdata = trServiceDM.GetDataInfo2(qdata);
                        var data = trServiceDM.GetTransportationRecords(qdata.PlateNumber);

                    }
                    #endregion


                }
                if (qdata.ProcessStatus == 6 && qdata.Inside == 1 && qdata.Finish == 1 && qdata.State == 1)
                {

                    //衡实时信息
                    _hubContext.Clients.All.SendAsync("ReceiveMessage", "HengQ", qdata.ToJson());
                    #region 拦截同一时间多次推送的
                    string key = qdata.PlateNumber + "pz";
                    if (!TimeLj(key))
                    {
                        //皮重
                        rdata = trServiceDM.GetDataInfo2(qdata);
                        //var data = trServiceDM.GetTransportationRecords(qdata.PlateNumber);

                        #region 打印
                        int? cartype = carServiceDM.GetCarType(qdata.PlateNumber);
                        if (cartype == 1 || cartype == 2 && (qdata.ClassName == 1 || qdata.ClassName == 2))
                        {
                            ShowMsg("打印开始-------------------------------------------------------------------------------------");
                            //获取打印数据
                            var print = trServiceDM.GetPrint(qdata);
                            ShowMsg("打印数据:" + print.ToJson());
                            if (print != null)
                            {
                                //打印
                                SendClientMsg(print.ToJson(), "print_pro");
                            }

                            ShowMsg("打印结束-------------------------------------------------------------------------------------");
                        }
                        #endregion
                    }
                    #endregion


                }
                if (qdata.ProcessStatus == 8)
                {

                    #region 拦截同一时间多次推送的
                    string key = qdata.PlateNumber + "cc";
                    if (!TimeLj(key))
                    {
                        //出厂
                        rdata = trServiceDM.GetDataInfo3(qdata);

                        #region 上报
                        int? cartype = carServiceDM.GetCarType(qdata.PlateNumber);

                        if (cartype == 1)
                        {
                            ShowMsg("上报开始-------------------------------------------------------------------------------------");
                            //获取上传数据
                            var upload = trServiceDM.GetScData(qdata);
                            ShowMsg("上报数据:" + upload.ToJson());
                            if (upload != null)
                            {
                                //上报
                                SendClientMsg(upload.ToJson(), "report_pro");
                            }


                            ShowMsg("上报开始-------------------------------------------------------------------------------------");
                        }
                        #endregion
                    }
                    #endregion


                }

                return rdata;

            }
            catch (Exception ex)
            {
                ShowMsg("TMV解析错误：" + ex.Message);
                return new ResultInfo() { Error = "5", Message = "TMV解析错误：" + ex.Message };
            }
        }
        static bool TimeLj(string key)
        {
            bool bl = false;
            var bk = _memoryCache.Get(key);
            if (bk != null)
            {
                TimeSpan ts1 = DateTime.Now - Convert.ToDateTime(bk);
                if (ts1.Seconds < 10)
                {
                    _memoryCache.Set(key, DateTime.Now, TimeSpan.FromSeconds(180));
                    bl = true;
                }
            }
            else
            {
                _memoryCache.Set(key, DateTime.Now, TimeSpan.FromSeconds(180));
            }
            return bl;
        }
        static void ShowMsg(string s)
        {
            Furion.Logging.Log.Information(s);
        }

        /// <summary>
        /// 回应动作
        /// </summary>
        /// <param name="socket"></param>
        /// <param name="msg"></param>
        private static void Send(Socket socket, string msg)
        {
            try
            {
                Byte[] bytesSent = Encoding.GetEncoding("GBK").GetBytes(msg);
                socket.Send(bytesSent, bytesSent.Length, 0);
                ShowMsg($"回复客户消息成功：客户Ip{socket.RemoteEndPoint.ToString()},回复内容 ：{msg}");
            }
            catch (Exception ex)
            {
                ShowMsg($"回复客户消息异常：{ex.Message}");
            }
        }
        /// <summary>
        /// 回复客户端对应消息
        /// </summary>
        /// <param name="msg"></param>
        /// <param name="ip">回复的客户端业务服务IP地址</param>
        /// <param name="code">回复客户端业务编码</param>
        private static void SendClientMsg(string msg, string code)
        {
            try
            {
                #region 根据业务回复socket客户端消息

                //根据ip或者编码查询相关业务的客户端socket配置
                var socketConfig = socketConfigService.GetSocketConfig("", code);
                if (!socketConfig.IsSuccess)
                {
                    ShowMsg("没有找到相关客户端配置信息，请查看配置信息");
                }
                else
                {
                    var client = clientScoket.Where(x => x.RemoteEndPoint.ToString().Substring(0, x.RemoteEndPoint.ToString().IndexOf(':')) == socketConfig.Data.Ip).First();
                    if (client != null)
                    {
                        Send(client, msg);
                    }
                    else
                    {
                        ShowMsg("没有找到相关客户端配置信息，请查看配置信息");
                    }
                }
                #endregion
            }
            catch (Exception e)
            {
                ShowMsg($"回复客户消息异常：{e.Message},业务编码：{code}");
            }

        }
    }
}
